package com.gin.kotlin.gf2gamecommunity.base.livedata

import androidx.lifecycle.MutableLiveData
import com.gin.kotlin.gf2gamecommunity.app.App
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class ParamCachedLiveData<T, D, P>(
    private val requestMethod: ParamCachedLiveData<T, D, P>.(P) -> Call<T>,
    private val bodyTransform: ParamCachedLiveData<T, D, P>.(T) -> D?,
    private val defaultExpire: Long = 300L,
) {
    private val liveDataMap = hashMapOf<String, MutableLiveData<CachedData<D>>>()
    private val loadingMap = hashMapOf<String, Boolean>()

    private fun liveData(param: P) = liveDataMap[param.toString()] ?: MutableLiveData<CachedData<D>>().also { liveDataMap[param.toString()] = it }

    fun fetch(param: P, force: Boolean = false, expire: Long = defaultExpire): MutableLiveData<CachedData<D>> {
        val liveData = liveData(param)
        val loading = loadingMap[param.toString()] == true
        if (loading) return liveData
        val cachedData = liveData.value
        if (!force && cachedData != null && System.currentTimeMillis() / 1000 - cachedData.timestamp < expire) return liveData

        loadingMap[param.toString()] = true

        requestMethod(param).enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                loadingMap[param.toString()] = false
                val code = response.code()

                if (code == 200) {
                    // 请求成功更新数据和上次成功时间
                    liveData.value = CachedData(response.body()?.let { bodyTransform(it) })
                } else {
                    // 请求失败
                    App.toast("$code: ${response.message()}")
                }
            }

            override fun onFailure(call: Call<T>, throwable: Throwable) {
                loadingMap[param.toString()] = false
                App.onFailed(throwable)
            }
        })


        return liveData
    }


    companion object {
        private val TAG = ParamCachedLiveData::class.java.simpleName
    }

    data class CachedData<T>(
        val data: T?,
        val timestamp: Long = System.currentTimeMillis() / 1000,
    )
}